package com.smile.service.impl;

import cn.dev33.satoken.spring.context.path.ApplicationContextPathLoading;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dtflys.forest.annotation.Get;
import com.dtflys.forest.annotation.Trace;

import com.smile.api.OperateLogApi;
import com.smile.api.OssApi;
import com.smile.commons.action.ActionUtils;
import com.smile.commons.file.FileUtils;
import com.smile.commons.page.MyBatisPlusPageConverter;
import com.smile.commons.page.R;
import com.smile.commons.time.TimeUtils;
import com.smile.file.uitl.MinioUtil;
import com.smile.mapper.*;
import com.smile.model.domain.*;
import com.smile.model.dto.request.*;
import com.smile.model.response.response.*;
import com.smile.request.AddOperateLogRequest;
import com.smile.service.AirportService;
import com.smile.service.DroneService;
import com.smile.service.FlightTaskProcessService;
import com.smile.service.MediaService;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.ZipParameters;
import org.apache.catalina.User;
import org.bouncycastle.math.raw.Mod;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public class MediaServiceImpl implements MediaService {

    @Autowired
    private DroneMapper droneMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MediaMapper mediaMapper;

    @Autowired
    private AirportMapper airportMapper;


    @Autowired
    private AirLineMapper airlineMapper;

    @Autowired
    private DeviceModelMapper deviceModelMapper;
    @Autowired
    private OssApi minioApi;
    @Autowired
    private InspectionTaskMapper inspectionTaskMapper;
    @Autowired
    private ApplicationContextPathLoading getApplicationContextPathLoading;

    @Autowired
    private OrganizationMapper organizationMapper;
    @Override
    public List<GetMediaDeviceResponseDTO> getDeviceList(GetMediaDeviceRequestDTO getMediaDeviceRequestDTO) {
        Long userId = Long.valueOf(StpUtil.getLoginId().toString());
        SmilePlusUser user = userMapper.selectById(userId);
        Long organizationId = user.getOrganizationId();
        System.out.println("organizationId:"+organizationId);
        QueryWrapper<FeisuanDrone> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(getMediaDeviceRequestDTO.getDeviceName())) {
            queryWrapper.like("drone_name", getMediaDeviceRequestDTO.getDeviceName());
        }


        SmilePlusOrganization smilePlusOrganization = organizationMapper.selectById(organizationId);
        if (smilePlusOrganization == null) throw new RuntimeException("组织不存在!");

        // 当前组织的祖籍字段
        String ancestors = smilePlusOrganization.getAncestors();
        String[] orgIds = ancestors.split(",");

        // 查询所有的下级组织
        List<SmilePlusOrganization> childOrgs = organizationMapper.selectList(new LambdaQueryWrapper<SmilePlusOrganization>() {{
            likeRight(SmilePlusOrganization::getAncestors, ancestors + ",");
        }});
        List<Long> ids = childOrgs.stream().map(SmilePlusOrganization::getId).collect(Collectors.toList());
        ids.add(organizationId);

        System.out.println("childOrgs:"+childOrgs);
        queryWrapper.isNotNull("media_upload_time");
        queryWrapper.in("organization_id", ids);
        List<FeisuanDrone> droneList = droneMapper.selectList(queryWrapper);
        List<GetMediaDeviceResponseDTO> getMediaDeviceResponseDTOList = new ArrayList<>();
        for (FeisuanDrone drone : droneList) {
            GetMediaDeviceResponseDTO getMediaDeviceResponseDTO = new GetMediaDeviceResponseDTO();
            getMediaDeviceResponseDTO.setId(drone.getId());
            getMediaDeviceResponseDTO.setDeviceName(drone.getDroneName());
            getMediaDeviceResponseDTO.setMediaUploadTime(drone.getMediaUploadTime());
            getMediaDeviceResponseDTO.setDeviceType(1);
            getMediaDeviceResponseDTOList.add(getMediaDeviceResponseDTO);
        }
        return getMediaDeviceResponseDTOList;
    }

    @Override
    public Page<GetMediaResponseDTO> getMediaDirectory(GetMediaRequestDTO getMediaRequestDTO) {
        QueryWrapper<FeisuanMedia> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("drone_id", getMediaRequestDTO.getDeviceId());
        queryWrapper.eq("parent_id", getMediaRequestDTO.getParentId());
        if (ObjectUtil.isNotEmpty(getMediaRequestDTO.getFileName())) {
            queryWrapper.like("file_name", getMediaRequestDTO.getFileName());
        }

        if (ObjectUtil.isNotEmpty(getMediaRequestDTO.getFileType())) {
            queryWrapper.like("file_type", getMediaRequestDTO.getFileType());
        }
        queryWrapper.orderByDesc("id");
        Page<FeisuanMedia> page = mediaMapper.selectPage(new Page<>(getMediaRequestDTO.getCurrentPage(), getMediaRequestDTO.getPageSize()), queryWrapper);
        Page<GetMediaResponseDTO> getAirportListResponseDTOPage = MyBatisPlusPageConverter.convertPage(page, GetMediaResponseDTO.class);
        getAirportListResponseDTOPage.setRecords(page.getRecords().stream().map(i->{
            GetMediaResponseDTO  getMediaResponseDTO = BeanUtil.copyProperties(i,GetMediaResponseDTO.class);
            if (ObjectUtil.isNotNull(i.getFileSize()) && i.getFileSize() > 0) {
                getMediaResponseDTO.setFileSize(formatBytes(i.getFileSize()));
            }else{
                getMediaResponseDTO.setFileSize(null);
            }
            return getMediaResponseDTO;
        }).collect(Collectors.toList()));

//        GetAirportListResponseDTO getAirportListResponseDTO = BeanUtil.copyProperties(i, GetAirportListResponseDTO.class);

        return getAirportListResponseDTOPage;
    }

    @Override
    public List<GetMediaResponseDTO> getMediaDirectoryAll(GetMediaRequestDTO getMediaRequestDTO) {
        QueryWrapper<FeisuanMedia> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("drone_id", getMediaRequestDTO.getDeviceId());
        queryWrapper.eq("parent_id", getMediaRequestDTO.getParentId());
        if (ObjectUtil.isNotEmpty(getMediaRequestDTO.getFileName())) {
            queryWrapper.like("file_name", getMediaRequestDTO.getFileName());
        }
        if (ObjectUtil.isNotEmpty(getMediaRequestDTO.getFileType())) {
            queryWrapper.like("file_type", getMediaRequestDTO.getFileType());
        }
        queryWrapper.orderByDesc("id");
        List<FeisuanMedia> list = mediaMapper.selectList(queryWrapper);
        list.forEach(i->{

        });
//        Page<GetMediaResponseDTO> getAirportListResponseDTOPage = MyBatisPlusPageConverter.convertPage(page, GetMediaResponseDTO.class);
        List<GetMediaResponseDTO> getAirportListResponseDTOPage = BeanUtil.copyToList(list, GetMediaResponseDTO.class);
        getAirportListResponseDTOPage.stream().map(i->{
            if (i.getSuffix().equals("mp4")){
                i.setVideoUrl(i.getFileUrl());
                i.setFileUrl("http://192.168.0.80:9000/my-bucket/wayline/2025-08-29T14:21:14.328899100/92746c40-ba12-4ce4-b65e-7b686322ed61/DJI_202508291448_003_92746c40-ba12-4ce4-b65e-7b686322ed61/DJI_20250829144932_0001_V.jpeg");
            }
          return i;
        }).collect(Collectors.toList());
        return getAirportListResponseDTOPage;
    }


    @Override
    public GetMediaInfoResponseDTO getMediaInfo(Long mediaId) {

        FeisuanMedia media = mediaMapper.selectById(mediaId);
        GetMediaInfoResponseDTO getMediaResponseDTO = new GetMediaInfoResponseDTO();
        if (ObjectUtil.isNotNull(media)) {
            getMediaResponseDTO.setTakeTime(media.getTakeTime());
            QueryWrapper<FeisuanInspectionTask> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("flight_id", media.getFlightId());
            queryWrapper.last("limit 1");
            FeisuanInspectionTask feisuanInspectionTask = inspectionTaskMapper.selectOne(queryWrapper);
            if (ObjectUtil.isNotNull(feisuanInspectionTask)) {
                FeisuanAirline feisuanAirline = airlineMapper.selectById(feisuanInspectionTask.getAirlineId());
                if (ObjectUtil.isNotNull(feisuanAirline)) {
                    getMediaResponseDTO.setAirlineName(feisuanAirline.getAirlineName());
                }
            }

            QueryWrapper<FeisuanDeviceModel> deviceModelQueryWrapper = new QueryWrapper<>();
            deviceModelQueryWrapper.eq("device_model_key", media.getDroneModelKey());
            deviceModelQueryWrapper.last("limit 1");
            FeisuanDeviceModel deviceModel = deviceModelMapper.selectOne(deviceModelQueryWrapper);
            if(ObjectUtil.isNotNull(deviceModel)){
                getMediaResponseDTO.setDeviceModel(deviceModel.getModelName());
            }
            getMediaResponseDTO.setTaskName(media.getPlanName());
            getMediaResponseDTO.setFileName(media.getFileName());
            getMediaResponseDTO.setFileType(media.getFileType());
            getMediaResponseDTO.setFileUrl(media.getFileUrl());
            getMediaResponseDTO.setFlightId(media.getFlightId());
            getMediaResponseDTO.setSuffix(media.getSuffix());
            getMediaResponseDTO.setLatitude(media.getLatitude());
            getMediaResponseDTO.setLongitude(media.getLongitude());
            getMediaResponseDTO.setRelativeAltitude(media.getRelativeAltitude());
            getMediaResponseDTO.setAbsoluteAltitude(media.getAbsoluteAltitude());
            getMediaResponseDTO.setId(Long.valueOf(media.getId()));
            getMediaResponseDTO.setResolution(media.getResolution());
            if(ObjectUtil.isNotNull(media.getDuration())){
                getMediaResponseDTO.setDuration(media.getDuration().toString());
            }
            if(ObjectUtil.isNotNull(media.getFileSize())){

                getMediaResponseDTO.setFileSize(formatBytes(media.getFileSize()));
            }

            FeisuanAirport airport = airportMapper.selectById(media.getAirportId());

//            getMediaResponseDTO.
            if (ObjectUtil.isNotNull(airport)) {
                getMediaResponseDTO.setAddress(airport.getAddress());
            }
            getMediaResponseDTO.setTakeTime(media.getTakeTime());
        }
        return getMediaResponseDTO;
    }
    public static String formatBytes(long bytes) {
        if (bytes < 1024) {
            return bytes + " B";
        }
        double kb = bytes / 1024.0;
        if (kb < 1024) {
            return String.format("%.2f KB", kb);
        }
        double mb = kb / 1024.0;
        return String.format("%.2f MB", mb);
    }
    @Override
    public GetMediaShareResponseDTO addMediaShare(AddMediaShareRequestDTO shareRequestDTO) {
        FeisuanMediaShare feisuanMediaShare = new FeisuanMediaShare();
        feisuanMediaShare.setCreateTime(LocalDateTime.now());
        feisuanMediaShare.setFileIds(shareRequestDTO.getFileIds());
        feisuanMediaShare.setCode(shareRequestDTO.getCode());
        feisuanMediaShare.setShareUserId((Long) StpUtil.getLoginId());
        feisuanMediaShare.setIsEncrypted(shareRequestDTO.getIsEncrypted());
        feisuanMediaShare.setPassword(shareRequestDTO.getPassword());
        feisuanMediaShare.setExpiredTime(shareRequestDTO.getExpiredTime());
        GetMediaShareResponseDTO getMediaShareResponseDTO = new GetMediaShareResponseDTO();
        return getMediaShareResponseDTO;
    }

    @Override
    public Boolean updateMedia(GetMediaRequestDTO getMediaRequestDTO) {

        UpdateWrapper<FeisuanMedia> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", getMediaRequestDTO.getId());
        updateWrapper.set("file_name", getMediaRequestDTO.getFileName());
        int result = mediaMapper.update(new FeisuanMedia(), updateWrapper);
        if (result > 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Boolean deleteMedia(GetMediaRequestDTO getMediaRequestDTO) {

        UpdateWrapper<FeisuanMedia> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", getMediaRequestDTO.getId());
//        updateWrapper.set("file_name",getMediaRequestDTO.getFileName());
        int result = mediaMapper.deleteById(getMediaRequestDTO);
        if (result > 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public Boolean batchDeleteMedia(GetMediaRequestDTO getMediaRequestDTO) {

        UpdateWrapper<FeisuanMedia> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", getMediaRequestDTO.getId());
//        updateWrapper.set("file_name",getMediaRequestDTO.getFileName());
        List<Long> ids = getMediaRequestDTO.getIds();

        for (Long id : ids) {
            int result = mediaMapper.deleteById(id);
        }
        return true;
    }

    @Override
    public String batchDownload(GetMediaRequestDTO getMediaRequestDTO) {

        UpdateWrapper<FeisuanMedia> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", getMediaRequestDTO.getId());
//        updateWrapper.set("file_name",getMediaRequestDTO.getFileName());
        List<Long> ids = getMediaRequestDTO.getIds();
        List<FeisuanMedia> feisuanMediaList = mediaMapper.selectBatchIds(ids);
        String zipFileName = "compressed_" + System.currentTimeMillis() + ".zip";
        String outputPath = "file/"+zipFileName;
        String downloadDir = "file/downloads_" + System.currentTimeMillis();
        List<String> zipLst = new ArrayList<>();
        try {
            Path dirPath = Paths.get(downloadDir);
            Files.createDirectory(dirPath);
        }catch (IOException e) {}
        createZipDirectory(downloadDir,feisuanMediaList);

        try {
            Boolean res = zipDirectory(downloadDir, outputPath);
            System.out.println("压缩结果"+res);
            File file1 = new File(outputPath);
            MultipartFile multipartFile = FileUtils.fileToMultipartFile(file1, "file");
            MinioUtil minioUtil = new MinioUtil();
            Map<String, Object> fileInfo = minioUtil.uploadFile(multipartFile, "my-bucket", "zip");
            if (fileInfo != null) {
                String url = fileInfo.get("url").toString();
                return url;
            }
        }catch (IOException e) {

        }
        return outputPath;
    }
    public void createZipDirectory(String dir,List<FeisuanMedia> feisuMediaList) {
        Path dirPath = Paths.get(dir);
        try {
            for (FeisuanMedia feisuanMedia : feisuMediaList) {
                if(feisuanMedia.getFileType() ==1){
                    //创建目录
                    String pathOne = dir+"/"+feisuanMedia.getFileName();

                    try {
                        Path directoryPath = Paths.get(pathOne);
                        Files.createDirectories(directoryPath); // 创建多级目录
                    } catch (IOException e) {
                        System.out.println(e.getMessage());
                    }
                    QueryWrapper<FeisuanMedia> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("parent_id", feisuanMedia.getId());
                    List<FeisuanMedia> feisuanMediaList2 = mediaMapper.selectList(queryWrapper);
                    createZipDirectory(pathOne,feisuanMediaList2);
                }else{
                    String fileUrl = feisuanMedia.getFileUrl();
                    String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
                    Path filePath = dirPath.resolve(fileName);
                    try (InputStream in = new URL(fileUrl).openStream()) {
                        Files.copy(in, filePath);
                    }catch (IOException e) {
                        System.out.println(e.getMessage());
                    }
                }
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }

    @Override
    public String directoryDownload(GetMediaRequestDTO getMediaRequestDTO) {
        QueryWrapper<FeisuanMedia> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", getMediaRequestDTO.getId());
        queryWrapper.groupBy("file_name");
        List<FeisuanMedia> feisuanMediaList = mediaMapper.selectList(queryWrapper);
        System.out.println("文件数量："+feisuanMediaList.size());
        if (ObjectUtil.isNull(feisuanMediaList)) {
            throw new RuntimeException("文件不存在");
        }
        String zipFileName = "compressed_" + System.currentTimeMillis() + ".zip";
        String outputPath = "file/"+zipFileName;
        String downloadDir = "file/downloads_" + System.currentTimeMillis();
        try {
            Path dirPath = Paths.get(downloadDir);
            Files.createDirectory(dirPath);
        }catch (IOException e) {
            System.out.println(e.getMessage());
        }
        createZipDirectory(downloadDir,feisuanMediaList);

        try {
            Boolean res = zipDirectory(downloadDir, outputPath);
            File file1 = new File(outputPath);
            MultipartFile multipartFile = FileUtils.fileToMultipartFile(file1, "file");
            MinioUtil minioUtil = new MinioUtil();
            Map<String, Object> fileInfo = minioUtil.uploadFile(multipartFile, "my-bucket", "zip");
            if (fileInfo != null) {
                String url = fileInfo.get("url").toString();
                return url;
            }
        }catch (IOException e) {

        }
        return outputPath;
    }

    public String directoryDownload2(GetMediaRequestDTO getMediaRequestDTO) {

        UpdateWrapper<FeisuanMedia> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", getMediaRequestDTO.getId());
        List<Long> ids = getMediaRequestDTO.getIds();
        List<String> feisuanMediaList = mediaMapper.selectBatchIds(ids).stream()
                .map(FeisuanMedia::getFileUrl)
                .collect(Collectors.toList());
        String zipFileName = "compressed_" + System.currentTimeMillis() + ".zip";
        String outputPath = "file";
        String downloadDir = "file/downloads_" + System.currentTimeMillis();
        List<String> zipLst = new ArrayList<>();
        Path dirPath = Paths.get(downloadDir);
        try {
            Files.createDirectory(dirPath);

            for (String fileUrl : feisuanMediaList) {
                String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);
                Path filePath = dirPath.resolve(fileName);

                try (InputStream in = new URL(fileUrl).openStream()) {
                    Files.copy(in, filePath);
                    zipLst.add(downloadDir + "/" + fileName);
                }
            }
        } catch (Exception e) {

        }
        File zipFile = new File(outputPath, zipFileName);
        try (ZipFile zip = new ZipFile(zipFile)) {
            ZipParameters parameters = new ZipParameters();
            parameters.setIncludeRootFolder(false);

            for (String file : zipLst) {
                File file1 = new File(file);
                if (file1.isDirectory()) {
                    zip.addFolder(file1, parameters);
                } else {
                    zip.addFile(file1, parameters);
                }
            }

            File file1 = new File("file/"+zipFileName);
            System.out.println("file/"+zipFileName);
            MultipartFile multipartFile = FileUtils.fileToMultipartFile(file1, "file");
            System.out.println(multipartFile.getSize());
            MinioUtil minioUtil = new MinioUtil();
            Map<String, Object> fileInfo = minioUtil.uploadFile(multipartFile,"my-bucket","zip");
            if (fileInfo != null) {
                String url = fileInfo.get("url").toString();
                return url;
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return  "file/" + zipFileName;
    }

    public static boolean zipDirectory(String sourceDir, String outputZip) {
        try (FileOutputStream fos = new FileOutputStream(outputZip);
             ZipOutputStream zos = new ZipOutputStream(fos)) {

            File fileToZip = new File(sourceDir);
            zipFile(fileToZip, fileToZip.getName(), zos);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    private static void zipFile(File fileToZip, String fileName, ZipOutputStream zos) throws IOException {
        if (fileToZip.isHidden()) return;

        if (fileToZip.isDirectory()) {
            if (fileName.endsWith("/")) {
                zos.putNextEntry(new ZipEntry(fileName));
                zos.closeEntry();
            } else {
                zos.putNextEntry(new ZipEntry(fileName + "/"));
                zos.closeEntry();
            }

            File[] children = fileToZip.listFiles();
            for (File childFile : children) {
                zipFile(childFile, fileName + "/" + childFile.getName(), zos);
            }
            return;
        }

        try (FileInputStream fis = new FileInputStream(fileToZip)) {
            ZipEntry zipEntry = new ZipEntry(fileName);
            zos.putNextEntry(zipEntry);
            byte[] bytes = new byte[1024];
            int length;
            while ((length = fis.read(bytes)) >= 0) {
                zos.write(bytes, 0, length);
            }
        }
    }
}
